package com.canyou.aspect;

import cn.hutool.crypto.SecureUtil;
import com.canyou.utils.JsonUtils;
import com.canyou.utils.RedisUtils;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.UUID;

import static com.canyou.api.ResponseBO.repeatSubmit;

/**
 * @author cd
 * @date 2019/6/10
 */
@Aspect
@Component
@Slf4j
@Order(value = 1)
public class RepeatSubmitAspect {

    public static final int LOCK_SECONDS = 5;

    @Pointcut("@annotation(io.swagger.annotations.ApiOperation)")
    public void pointCut() {
    }

    @Around("@annotation(apiOperation)")
    public Object around(ProceedingJoinPoint joinPoint, ApiOperation apiOperation) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String method = request.getMethod();
        String path = request.getServletPath();
        // POST提交才拦截
        if (HttpMethod.POST.matches(method)) {
            // 此处可以用token或者JSessionId
            String token = request.getHeader("Authorization");
            Object[] obj = JsonUtils.transFile(joinPoint.getArgs());
            String params = JsonUtils.toString(obj);
            String key = SecureUtil.md5(token + "_" + path + "_" + request.getMethod() + params);
            String clientId = UUID.randomUUID().toString();
            boolean isSuccess = RedisUtils.setIfAbsent(key, clientId, (long) LOCK_SECONDS);
            log.debug("tryLock key = [{}], clientId = [{}]", key, clientId);
            if (isSuccess) {
                log.debug("tryLock success, key = [{}], clientId = [{}]", key, clientId);
                // 获取锁成功
                try {
                    // 执行进程
                    return joinPoint.proceed();
                } finally {
                    // 解锁
                    RedisUtils.delIfAbsent(key);
                    log.debug("releaseLock success, key = [{}], clientId = [{}]", key, clientId);
                }
            } else {
                // 获取锁失败，认为是重复提交的请求
                log.info("tryLock error, key = [{}]", key);
                return repeatSubmit("重复请求，请稍后再试");
            }
        } else {
            return joinPoint.proceed();
        }
    }
}
